<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.0.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/wang-cheng/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/wang-cheng/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/wang-cheng/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/wang-cheng/images/logo.svg" color="#222">

<link rel="stylesheet" href="/wang-cheng/css/main.css">


<link rel="stylesheet" href="/wang-cheng/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"cheng-wang123.gitee.io","root":"/wang-cheng/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="并发、并行、串行的区别串行在时间上不可重叠，前一个任务没搞定，下一个任务只能等着 并行在时间上重叠，两个任务在同一时刻互不干扰的同时执行 并发允许两个任务彼此干扰。统一时间点、只有一个任务运行，交替执行 并发的三大特性缓存导致了可见性问题，线程切换带来了原子性问题，编译优带来了有序性问题  原子性  原子性是指在一个操作中cpu不可以在中途暂停然后再调度，即不被中断操作，要不全部执行完成，要不都不">
<meta property="og:type" content="article">
<meta property="og:title" content="面试题(四)">
<meta property="og:url" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/index.html">
<meta property="og:site_name" content="诚の博客">
<meta property="og:description" content="并发、并行、串行的区别串行在时间上不可重叠，前一个任务没搞定，下一个任务只能等着 并行在时间上重叠，两个任务在同一时刻互不干扰的同时执行 并发允许两个任务彼此干扰。统一时间点、只有一个任务运行，交替执行 并发的三大特性缓存导致了可见性问题，线程切换带来了原子性问题，编译优带来了有序性问题  原子性  原子性是指在一个操作中cpu不可以在中途暂停然后再调度，即不被中断操作，要不全部执行完成，要不都不">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B.png">
<meta property="og:image" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/%E4%B8%89%E7%BA%A7%E7%BC%93%E5%AD%98.png">
<meta property="og:image" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/Bean%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B.png">
<meta property="og:image" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/%E4%B8%89%E7%BA%A7%E7%BC%93%E5%AD%98%E8%A7%A3%E9%87%8A.png">
<meta property="og:image" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/Bean%E7%9A%84AOP%E6%B5%81%E7%A8%8B.png">
<meta property="article:published_time" content="2022-03-20T09:15:06.000Z">
<meta property="article:modified_time" content="2022-05-02T07:58:40.347Z">
<meta property="article:author" content="王诚">
<meta property="article:tag" content="面试题">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B.png">

<link rel="canonical" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>面试题(四) | 诚の博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/wang-cheng/atom.xml" title="诚の博客" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/wang-cheng/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">诚の博客</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">记录学习中的点点滴滴</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/wang-cheng/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/wang-cheng/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/wang-cheng/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/wang-cheng/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          面试题(四)
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-20 17:15:06" itemprop="dateCreated datePublished" datetime="2022-03-20T17:15:06+08:00">2022-03-20</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-05-02 15:58:40" itemprop="dateModified" datetime="2022-05-02T15:58:40+08:00">2022-05-02</time>
              </span>

          
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h2 id="并发、并行、串行的区别"><a href="#并发、并行、串行的区别" class="headerlink" title="并发、并行、串行的区别"></a><strong>并发、并行、串行的区别</strong></h2><p>串行在时间上不可重叠，前一个任务没搞定，下一个任务只能等着</p>
<p>并行在时间上重叠，两个任务在同一时刻互不干扰的同时执行</p>
<p>并发允许两个任务彼此干扰。统一时间点、只有一个任务运行，交替执行</p>
<h2 id="并发的三大特性"><a href="#并发的三大特性" class="headerlink" title="并发的三大特性"></a><strong>并发的三大特性</strong></h2><p>缓存导致了可见性问题，线程切换带来了原子性问题，编译优带来了有序性问题</p>
<ul>
<li>原子性</li>
</ul>
<p>原子性是指在一个操作中cpu不可以在中途暂停然后再调度，即不被中断操作，要不全部执行完成，要不都不执行。</p>
<figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">i++</span><br><span class="line"><span class="bullet">1.</span> 将i从主存读到工作内存中的副本中</span><br><span class="line"><span class="bullet">2.</span> +1的运算</span><br><span class="line"><span class="bullet">3.</span> 将结果写入工作内存</span><br><span class="line">原子性就是指这三步操作要么一起执行，要么不执行，中间不可以中断</span><br></pre></td></tr></table></figure>
<p>synchronized关键字可以保证原子性</p>
<ul>
<li>可见性</li>
</ul>
<p>当多个线程访问同一个变量时，一个线程修改了这个变量的值，其他线程能够立刻看到修改的值</p>
<figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">4.</span> 将工作内存的值刷回到主存(什么时候刷入由操作系统决定，不确定的)</span><br><span class="line">可见性就是指第4步与第3步操作要么一块执行，要么不执行，中间不可以中断</span><br></pre></td></tr></table></figure>
<p>volatile、synchronized、final都可以保证可见性</p>
<ul>
<li>有序性</li>
</ul>
<p>虚拟机在进行代码编译时，对于那些改变顺序后不会对最终结果造成影响的代码，虚拟机不一定会按照我们写的代码的顺序来执行，有可能将他们重排序。实际上，对于有些代码进行重排序后，虽然对变量的值没有造成影响，但有可能会出现线程安全问题。<br><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">int</span> a = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">bool</span> flag = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span>()</span>&#123;</span><br><span class="line">    a = <span class="number">2</span>;</span><br><span class="line">    flag = <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">multiply</span>()</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(flag)&#123;</span><br><span class="line">        <span class="built_in">int</span> ret = a * a;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br>volatile、synchronized都可以保证有序性</p>
<p>write方法里的1和2做了重排序，线程1先对flag赋值为true，随后执行到线程2，ret直接计算出结果，再到线程1，这时候a才赋值为2，明显迟了一步。</p>
<p>volatile本身就包含了禁止指令重排序的语义，而synchronized关键字是由”一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则明确的</p>
<p>synochronized关键字同时满足以上三种特性，但volatile不满足原子性。</p>
<p>在某些情况下，volatile的同步机制的性能确实要优于锁(使用synchronized关键字或java.util.concurrent包里面的锁)，因为volatile的总开销要比锁低。</p>
<h2 id="为什么要用线程池？解释下线程池参数？"><a href="#为什么要用线程池？解释下线程池参数？" class="headerlink" title="为什么要用线程池？解释下线程池参数？"></a><strong>为什么要用线程池？解释下线程池参数？</strong></h2><ol>
<li><p>降低资源消耗；提高线程利用率，降低创建和销毁线程的消耗</p>
</li>
<li><p>提高效应速度；任务来了，直接有线程可用可执行，而不是先创建线程，再执行</p>
</li>
<li><p>提高线程的可管理性；线程是稀缺资源，使用线程池可以统一分配调优监控</p>
<ul>
<li><p><code>corePoolSize</code>代表核心线程数，也就是正常情况下创建工作的线程数，这些线程创建后并不会消除，而是一种常驻线程(随着线程池的回收一起回收掉)</p>
</li>
<li><p><code>maxinumPoolSize</code>代表的是最大线程数，它与核心线程数相对应，表示最大允许被创建的线程数，比如当前任务较多，将核心线程数都用完了，还无法满足需求时，此时就会创建新的线程，但是线程池内线程总数不会超过最大线程数</p>
</li>
<li><p><code>KeepAliveTime、unit</code>表示超过核心线程数之外的线程的空闲存活时间，也就是核心线程不会消除，但是超过核心线程数的部分线程如果空闲一定时间则会被清除，我们可以通过setKeepAliveTime来设置空闲时间</p>
</li>
<li><p><code>WorkQueue</code>用来存放待执行的任务，假设我们现在核心线程都已被使用，还有任务进来则全部放入队列(不会立即创建新的线程)，直到整个队列都被放满任务还再持续进入则会开始创建新的线程</p>
</li>
<li><p><code>ThreadFactory</code>实际上是一个线程工厂，用来生产线程执行任务。我们可以选择使用默认的创建工厂，产生的线程都会在同一个组内，拥有相同的优先级，且都不是守护线程。当然我们也可以选择自定义线程工厂，一般我们会根据业务来指定不同的线程工厂</p>
</li>
<li><p><code>Handler</code>任务拒绝策略，有两种情况，第一种是当我们调用shutdown等方法关闭线程池后，这时候即使线程池内部还有没执行完的任务在执行，但是由于线程池已经关闭，我们再继续向线程池提交任务就会遭到拒绝。另一种情况就是当达到最大线程数，线程池已经没有能力继续处理新提交的任务时，这是也会拒绝</p>
<ul>
<li><p>CallerRunsPolicy - 当触发拒绝策略，只要线程池没有关闭的话，则使用调用线程直接运行任务。一般并发比较小，性能要求不高，不允许失败。但是，由于调用者自己运行任务，如果任务提交速度过快，可能导致程序阻塞，性能效率上必然的损失较大</p>
</li>
<li><p>AbortPolicy - 丢弃任务，并抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常，否则会打断当前的执行流程，影响后续的任务执行。</p>
</li>
<li><p>DiscardPolicy - 直接丢弃，其他啥都没有</p>
<p>-DiscardOldestPolicy - 当触发拒绝策略，只要线程池没有关闭的话，丢弃阻塞队列 workQueue 中最老的一个任务，并将新任务加入</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<h2 id="简述线程池处理流程"><a href="#简述线程池处理流程" class="headerlink" title="简述线程池处理流程"></a><strong>简述线程池处理流程</strong></h2><img src="/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B.png" class title="线程池执行流程">
<h2 id="线程池中阻塞队列的作用？为什么是先添加队列而不是先创建最大线程"><a href="#线程池中阻塞队列的作用？为什么是先添加队列而不是先创建最大线程" class="headerlink" title="线程池中阻塞队列的作用？为什么是先添加队列而不是先创建最大线程"></a><strong>线程池中阻塞队列的作用？为什么是先添加队列而不是先创建最大线程</strong></h2><p>1、 一般的队列只能保证作为一个有限长度的缓冲区，如果超出了缓冲长度，就无法保留当前的任务了，阻塞队列通过阻塞可以保留住当前想要继续入队的任务。</p>
<p>阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程，使得线程进入wait状态，释放cpu资源。</p>
<p>阻塞队列自带阻塞和唤醒的功能，不需要额外处理，无任务执行时，线程池利用阻塞队列的take方法挂起，从而维持核心线程的存活、不至于一直占用cpu资源。</p>
<p>2、 在创建新线程的时候，是要获取全局锁的，这个时候其他的就得阻塞，影响了整体效率</p>
<p>就好比一个企业里面有10个(core)正式工的名额，最多招10个正式工，要是任务超过正式工人数(task&gt;core)的情况下，工厂领导(线程池)不是首先扩招工人，还是这10个人，但是任务可以稍微积压一下，即先放到队列去(代价低)。10个正式工慢慢干，迟早会干完的，要是任务还在继续增加，超过正式工的加班忍耐极限了(队列满了)，就得招外包帮忙了(注意是临时供)，要是正式工加上外包还是不能完成任务，那新来得任务就会被领导拒绝了(线程池的拒绝策略)</p>
<h2 id="线程池中线程复用原理"><a href="#线程池中线程复用原理" class="headerlink" title="线程池中线程复用原理"></a><strong>线程池中线程复用原理</strong></h2><p>线程池将线程和任务进行解耦，线程是线程，任务是任务，摆脱了之前通过Thread创建线程时的一个线程必须对应一个任务的限制。</p>
<p>在线程池中，同一个线程可以从阻塞队列中不断获取新任务来执行，其核心原理在于线程池对Thread进行了封装，并不是每次执行任务都会调用Thread.start()来创建新线程(不使用线程池的话，是用一个任务类去继承Thread或实现Runnable接口，将任务逻辑写在run方法内)，而是让每个线程去执行一个”循环任务”，在这个”循环任务”中不停检查是否有任务需要被执行，如果有则直接执行，也就是调用任务中的run方法(直接调run方法而不是调用start方法)，将run方法当成一个普通的方法执行，通过这种方式只使用固定的线程就将所有任务的run方法串联起来。</p>
<p>理解：真正的任务逻辑，并不是写在线程池中的run方法内，而是利用这些线程去调我任务里的这个run方法，从而执行我的任务逻辑。</p>
<h2 id="Spring是什么"><a href="#Spring是什么" class="headerlink" title="Spring是什么"></a><strong>Spring是什么</strong></h2><p>轻量级的开源的J2EE框架。它是一个容器框架，用来装javabean，中间层框架可以起到连接作用，比如说把Struts和hibernate粘合在一起运用，可以让我们的企业开发更快、更简洁</p>
<p>Spring是一个轻量级的控制反转和面向切面的容器框架</p>
<ul>
<li><p>从大小与开销两方面而言Spring都是轻量级的</p>
</li>
<li><p>通过控制反转的技术达到松耦合的目的</p>
</li>
<li><p>提供了面向切面编程的丰富支持，允许通过分离应用的业务逻辑与系统级服务进行内聚性(采用AOP的切面，专门用来做日志的工作。如果没有使用Spring，那么就需要在代码的许多地方都写入日志性的代码)的开发</p>
</li>
<li><p>包含并管理应用对象的配置和生命周期，这个意义上是一个容器</p>
</li>
<li><p>将简单的组件配置、组合成为复杂的应用(整合功能)，这个意义上是一个框架</p>
</li>
</ul>
<h2 id="对AOP的理解"><a href="#对AOP的理解" class="headerlink" title="对AOP的理解"></a><strong>对AOP的理解</strong></h2><p>系统是由许多不同的组件所组成的，每一个组件各负责一块特定功能。除了实现自身核心功能之外，这些组件还经常承担着额外的职责。例如日志、事务管理和安全这样的核心服务经常融入到自身具有核心业务逻辑的组件中去。这些系统服务经常被称为横切关注点，因为他们会跨越系统的多个组件。</p>
<p>当我们需要为分散的对象引入公共行为的时候，OOP则显得无能为力。也就是说，OOP允许你定义从上到下的关系，但并不适合定义从左到右的关系，例如日志功能。</p>
<p>日志代码往往水平地分散在所有对象层次中，而与它所散布到的对象的核心功能毫无关系。</p>
<p>在OOP设计中，它导致了大量代码的重复，而不利于各个模块的重用。</p>
<p>AOP：将程序中的交叉业务逻辑(比如日志、安全、事务等)，封装成一个切面，然后注入到目标对象中(具体业务逻辑)。AOP可以对某些对象或某个对象的功能进行增强，比如对象中的方法进行增强，可以在执行某个方法之前额外的做一些事，在某个方法执行之后额外做一些事情。</p>
<h2 id="对IOC的理解"><a href="#对IOC的理解" class="headerlink" title="对IOC的理解"></a><strong>对IOC的理解</strong></h2><p>容器概念、控制反转、依赖注入</p>
<p>IOC容器：实际上就是个map(key,value),里面存放的是各种对象(在xml里配置的bean节点、@Repository、@Service、@Controoler、@Component)，在项目启动的时候会读取配置文件里面的bean节点，根据全限定类名使用反射创建对象放在map里、扫描到打上上述注解的类，还是通过反射创建对象放到map中。</p>
<p>这个时候map里就有各种对象了，接下来我们在代码里需要用到里面的对象时，再通过DI注入(@Autowired、@Resource等注解，xml里bean节点内的ref属性，项目启动的时候会读取xml节点ref属性根据id注入，也会扫描这些注解，根据类型或id注入，id就是对象名)</p>
<p><strong>控制反转：</strong></p>
<p>没有引入IOC容器之前，对象A依赖于对象B，那么对象A在初始化或运行到某一点的时候，自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B，控制权都在自己手上。</p>
<p>引入IOC容器后，对象A与对象B之间失去了直接联系；当对象A运行到需要对象B的时候，IOC容器会主动去创建一个对象B注入到对象A需要的地方。</p>
<p>通过对比，不难看出对象A获得依赖对象B的过程，由主动行为变为了被动行为，控制权颠倒了，这就是”控制反转”这个名称的由来。</p>
<p>全部对象的控制权全部上缴给”第三方”IOC容器，所以，IOC容器成了整个系统的关键核心，它起到了一种类似”粘合剂”的作用，把系统中的所有对象粘合在一起发挥作用，如果没有这个”粘合剂”，对象与对象之间会彼此失去联系，这就是有人把IOC容器比喻成”粘合剂”的由来</p>
<p><strong>依赖注入：</strong></p>
<p>“获得依赖对象的过程被反转了”。控制被反转后，获得依赖对象地过程由自身管理变成了由IOC容器主动注入。依赖注入是实现IOC的方法，就是由IOC容器在运行期间，动态地将某种依赖关系注入到对象之中</p>
<h2 id="BeanFactory和ApplicationContext有什么区别"><a href="#BeanFactory和ApplicationContext有什么区别" class="headerlink" title="BeanFactory和ApplicationContext有什么区别"></a><strong>BeanFactory和ApplicationContext有什么区别</strong></h2><p>ApplicationContext是BeanFactory的子接口</p>
<p>ApplicationContext提供了更完整的功能(拓展了BeanFactory)：</p>
<ol>
<li><p>继承MessageSource，因此支持国际化</p>
</li>
<li><p>统一的资源文件访问方式</p>
</li>
<li><p>提供在监听器中注册bean的事件</p>
</li>
<li><p>同时加载多个配置文件</p>
</li>
<li><p>载入多个(有继承关系)上下文，使得每一个上下文都专注于一个特定的层次，比如应用的web层</p>
</li>
</ol>
<ul>
<li><p>BeanFactory采用的是延迟加载形式来注入Bean的，即只有在使用到某个Bean时(调用getBean())，才对该Bean进行加载实例化。这样，我们就不能发现一些存在的Spring的配置问题。如果Bean的某一属性没有注入，BeanFactory加载后，直至第一次使用调用getBean()方法才抛出异常</p>
</li>
<li><p>ApplicationContext，它是在容器启动时，一次性创建了所有Bean。这样，在容器启动时，我们就可以发现Spring中存在的配置错误，这样就有利于检查所依赖属性是否注入。ApplicationContext启动后预载入所有的单实例Bean，通过预载入单实例Bean，确保当你需要的时候，你就不用等待，因为他们已经创建好了。</p>
</li>
<li><p>相对于基本的BeanFactory，ApplicationContext唯一的不足是占用内存空间。当应用配置Bean较多时，程序启动较慢</p>
</li>
<li><p>BeanFactory通常以编程的方式被创建，ApplicationContext还能以声明的方式被创建，如使用ContextLoader</p>
</li>
<li><p>BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor(后置处理器)的使用，但两者的区别是：Beanfactory需要手动注册，而ApplicationContext则是自动注册</p>
</li>
</ul>
<h2 id="描述一下Spring-Bean的生命周期"><a href="#描述一下Spring-Bean的生命周期" class="headerlink" title="描述一下Spring Bean的生命周期"></a><strong>描述一下Spring Bean的生命周期</strong></h2><p>1、解析类得到BeanDefinition</p>
<p>2、 如果有多个构造方法，则要推断构造方法</p>
<p>3、 确定好构造方法后，进行实例化得到一个对象</p>
<p>4、 对对象中的加了@Autowired注解的属性进行填充</p>
<p>5、 回调Aware方法，比如BeanNameAware，BeanFactoryAware</p>
<p>6、 调用BeanPostProcessor的初始化前的方法</p>
<p>7、调用初始化方法</p>
<p>8、 调用BeanPostProcessor的初始化后的方法，在这里会进行AOP</p>
<p>9、 如果当前创建的bean是单例则会把bean放入单例池</p>
<p>10、 使用bean</p>
<p>11、 Spring容器关闭时调用disposableBean中的destory()方法</p>
<h2 id="解释下Spring支持的几种bean的作用域"><a href="#解释下Spring支持的几种bean的作用域" class="headerlink" title="解释下Spring支持的几种bean的作用域"></a><strong>解释下Spring支持的几种bean的作用域</strong></h2><ul>
<li><p>singleton：默认，每个容器中只有一个bean的实例，单例的模式由BeanFactory自身来维护。该对象的生命周期是与Spring IOC容器一致的(但在第一次被注入时才会创建)</p>
</li>
<li><p>prototype：为每一个bean请求提供一个实例。在每次注入时都会创建一个新的对象</p>
</li>
<li><p>request：bean被定义为在每个HTTP请求中创建一个单例对象，也就是说在单个请求中都会复用这一个单例对象。</p>
</li>
<li><p>session：与request范围类似，确保每个session中有一个bean的实例，在session过期后，bean会随之失效</p>
</li>
<li><p>application：bean被定义为在ServletContext(Servlet容器)的生命周期中复用一个单例对象</p>
</li>
<li><p>websocket：bean被定义为在websocket的生命周期中复用一个单例对象</p>
</li>
<li><p>global-session：全局作用域，global-session和Portlet应用相关(只与其有关)。当你的应用部署在Portlet容器中工作时，它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话，那么这个全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。</p>
</li>
</ul>
<h2 id="Spring框架中的单例Bean是线程安全的吗"><a href="#Spring框架中的单例Bean是线程安全的吗" class="headerlink" title="Spring框架中的单例Bean是线程安全的吗"></a><strong>Spring框架中的单例Bean是线程安全的吗</strong></h2><p><strong>不安全</strong></p>
<p>Spring中的Bean默认是单例模式的，框架并没有对bean进行多线程的封装处理。</p>
<p>如果Bean是有状态的，那就需要开发人员自己来进行线程安全的保证，最简单的办法就是改变Bean的作用域，把singleton改为prototyte，这样每次请求Bean就相当于是new Bean()，这样就保证线程安全了。</p>
<ul>
<li><p>有状态就是有数据存储功能</p>
</li>
<li><p>无状态就是不会保存数据，controller、service和dao层本身并不是线程安全的，只是如果只是调用里面的方法，而且多线程调用一个实例的方法，会在内存中复制变量，这是自己的线程的工作内存，是安全的。</p>
</li>
</ul>
<p>Dao会操作数据库Connection，Connection是带有状态的，比如说数据库事务，Spring的事务管理器使用ThreadLocal为不同线程维护了一套独立的Connection副本，保证线程之间不会互相影响(Spring是如何保证事务获取到同一个Connection的)</p>
<p>不要在bean中声明任何有状态的实例变量或类变量，如果必须如此，那么就使用ThreadLocal把变量变为线程私有，如果bean的实例变量或类变量需要在多个线程之间共享，那么就只能使用synchronized、local、CAS等这些实现线程同步的方法了。</p>
<h2 id="Spring框架中都用了哪些设计模式"><a href="#Spring框架中都用了哪些设计模式" class="headerlink" title="Spring框架中都用了哪些设计模式"></a><strong>Spring框架中都用了哪些设计模式</strong></h2><p>简单工厂：由一个工厂类根据传入的参数，动态决定应该创建哪一个产品类<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Spring中的BeanFactory就是简单工厂模式的体现，根据传入一个唯一的标识来获得Bean对象，但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定</span><br></pre></td></tr></table></figure></p>
<p>工厂方法：<br><figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">实现了FactoryBean接口得bean是一类叫做factory得bean。其特点是，spring会在使用<span class="built_in">getBean</span>()调用获得该bean时，会自动调用该bean的<span class="built_in">getObject</span>()方法，所以返回的不是factory的这个bean，而是这个bean<span class="selector-class">.getObject</span>()方法的返回值(这里的返回值可能是FactoryBean的bean对象，也可能是其他对象，这完全取决于你在实现它的bean.getObject方法中返回的什么)</span><br></pre></td></tr></table></figure></p>
<p>单例模式：保证一个类仅有一个实例，并提供一个访问它的全局访问点<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Spring对单例的实现：Spring中的单例模式完成了后半句话，即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例，这是因为Spring管理的是任意的java对象</span><br></pre></td></tr></table></figure></p>
<p>适配器模式：<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Spring定义了一个适配接口，使得每一种Controller有一种对应的适配器实现类，让适配器代替Controller执行相应的方法。这样在扩展Controller时，只需要增加一个适配器类就完成了SpringMVC的扩展了</span><br></pre></td></tr></table></figure></p>
<p>装饰器模式：动态地给一个对象添加一些额外的职责。就增强功能来说，Decorator模式相比生成子类更为灵活<br><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Spring中用到的包装器模式在类名上有两种表现：一种是类名中含有<span class="keyword">Wrapper</span>，另一种是类名中含有Decorator</span><br></pre></td></tr></table></figure></p>
<p>动态代理：<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">切面在应用运行的时刻被织入。一般情况下，在织入切面时，AOP容器会为目标对象创建动态的代理对象。SpringAOP就是以这种方式织入切面的。</span><br><span class="line"></span><br><span class="line">织入：把切面应用到目标对象并创建新的代理对象的过程</span><br></pre></td></tr></table></figure></p>
<p>观察者模式：<br><figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Spring的事件驱动模型使用的是观察者模式(监听器),Spring中Observer模式常用的地方是listener的实现。</span><br></pre></td></tr></table></figure></p>
<p>策略模式：<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力，Spring框架本身大量使用了Resource接口来访问底层资源</span><br></pre></td></tr></table></figure></p>
<h2 id="Spring-依赖注入中的循环依赖问题"><a href="#Spring-依赖注入中的循环依赖问题" class="headerlink" title="Spring 依赖注入中的循环依赖问题"></a><strong>Spring 依赖注入中的循环依赖问题</strong></h2><h3 id="三种循环依赖的情况"><a href="#三种循环依赖的情况" class="headerlink" title="三种循环依赖的情况"></a><strong>三种循环依赖的情况</strong></h3><ul>
<li><p>构造器的循环依赖：这种依赖spring是处理不了的，直接抛出BeanCurrentlylnCreationException异常。</p>
</li>
<li><p>单例模式下的setter循环依赖：通过“三级缓存”处理循环依赖，能处理。</p>
</li>
<li><p>非单例循环依赖：无法处理。原型(Prototype)的场景是不支持循环依赖的，通常会走到<code>AbstractBeanFactory</code>类中下面的判断，抛出异常。</p>
</li>
</ul>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Bean</span></span><br><span class="line">public class A &#123;</span><br><span class="line">    <span class="variable">@Autowire</span></span><br><span class="line">    private B b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">@Bean</span></span><br><span class="line">public class B &#123;</span><br><span class="line">    <span class="variable">@Autowire</span></span><br><span class="line">    private A a;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>也就是需要在A中注入B，在B中注入A，那么Spring在创建A的时候会出现这种现象：创建A实例后，在依赖注入时需要B，然后就去创建B，这时候发现又需要依赖注入 A ，这样就导致了循环依赖。</p>
<h3 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a><strong>解决方法</strong></h3><p>用三级缓存方式达到Bean提前曝光的目的。</p>
<p>Spring创建的过程简单的可以简单概括为 实例化——&gt;依赖注入——&gt;初始化。而Spring解决循环依赖的方法就是在实例化之后，依赖注入之前，将实例化的对象放到缓存中进行提前曝光，后边的对象则在实例化前，先到缓存中查找有无对应的实例化对象即可</p>
<img src="/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/%E4%B8%89%E7%BA%A7%E7%BC%93%E5%AD%98.png" class title="三级缓存">
<p>或者</p>
<img src="/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/Bean%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B.png" class title="Bean执行流程">
<p><strong>每一级缓存的作用：</strong><br><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">singletonObjects （一级缓存）它是我们最熟悉的朋友，俗称“单例池”“容器”，缓存创建完成单例<span class="keyword">Bean的地方。</span></span><br><span class="line"><span class="keyword"></span></span><br><span class="line">earlySingletonObjects（二级缓存）映射<span class="keyword">Bean的早期引用，也就是说在这个Map里的Bean不是完整的，甚至还不能称之为“Bean”，只是一个Instance.</span></span><br><span class="line"><span class="keyword"></span></span><br><span class="line">singletonFactories（三级缓存） 映射创建<span class="keyword">Bean的原始工厂</span></span><br></pre></td></tr></table></figure></p>
<img src="/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/%E4%B8%89%E7%BA%A7%E7%BC%93%E5%AD%98%E8%A7%A3%E9%87%8A.png" class title="三级缓存解释">
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">实例化 <span class="selector-tag">A</span>，此时 <span class="selector-tag">A</span> 还未完成属性填充和初始化方法（@<span class="selector-tag">PostConstruct</span>）的执行，<span class="selector-tag">A</span> 只是一个半成品。</span><br><span class="line"></span><br><span class="line">为 <span class="selector-tag">A</span> 创建一个 <span class="selector-tag">Bean</span>工厂，并放入到 <span class="selector-tag">singletonFactories</span> 中。</span><br><span class="line"></span><br><span class="line">发现 <span class="selector-tag">A</span> 需要注入 <span class="selector-tag">B</span> 对象，但是一级、二级、三级缓存均为发现对象 <span class="selector-tag">B</span>。</span><br><span class="line"></span><br><span class="line">实例化 <span class="selector-tag">B</span>，此时 <span class="selector-tag">B</span> 还未完成属性填充和初始化方法（@<span class="selector-tag">PostConstruct</span>）的执行，<span class="selector-tag">B</span> 只是一个半成品。</span><br><span class="line"></span><br><span class="line">为 <span class="selector-tag">B</span> 创建一个 <span class="selector-tag">Bean</span>工厂，并放入到 <span class="selector-tag">singletonFactories</span> 中。</span><br><span class="line"></span><br><span class="line">发现 <span class="selector-tag">B</span> 需要注入 <span class="selector-tag">A</span> 对象，此时在一级、二级未发现对象</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">A</span>，但是在三级缓存中发现了对象 <span class="selector-tag">A</span>，从三级缓存中得到对象 <span class="selector-tag">A</span>，并将对象 <span class="selector-tag">A</span> 放入二级缓存中，同时删除三级缓存中的对象 <span class="selector-tag">A</span>。（注意，此时的 <span class="selector-tag">A</span></span><br><span class="line"></span><br><span class="line">还是一个半成品，并没有完成属性填充和执行初始化方法）</span><br><span class="line"></span><br><span class="line">将对象 <span class="selector-tag">A</span> 注入到对象 <span class="selector-tag">B</span> 中。</span><br><span class="line"></span><br><span class="line">对象 <span class="selector-tag">B</span> 完成属性填充，执行初始化方法，并放入到一级缓存中，同时删除二级缓存中的对象 <span class="selector-tag">B</span>。（此时对象 <span class="selector-tag">B</span> 已经是一个成品）</span><br><span class="line"></span><br><span class="line">对象 <span class="selector-tag">A</span> 得到对象<span class="selector-tag">B</span>，将对象 <span class="selector-tag">B</span> 注入到对象 <span class="selector-tag">A</span> 中。（对象 <span class="selector-tag">A</span> 得到的是一个完整的对象 <span class="selector-tag">B</span>）</span><br><span class="line"></span><br><span class="line">对象 <span class="selector-tag">A</span>完成属性填充，执行初始化方法，并放入到一级缓存中，同时删除二级缓存中的对象 <span class="selector-tag">A</span>。</span><br></pre></td></tr></table></figure>
<p>Spring 在实例化对象的之后，就会为其创建一个 Bean 工厂，并将此工厂加入到三级缓存中。</p>
<p>因此，<code>Spring 一开始提前暴露的并不是实例化的 Bean，而是将 Bean 包装起来的 ObjectFactory</code>。为什么要这么做呢？</p>
<p>这实际上涉及到 AOP，<code>如果创建的 Bean 是有代理的，那么注入的就应该是代理 Bean，而不是原始的 Bean</code>。但是 Spring 一开始并不知道 Bean 是否会有循环依赖，通常情况下（没有循环依赖的情况下），Spring 都会在完成填充属性，并且执行完初始化方法之后再为其创建代理。但是，<code>如果出现了循环依赖的话，Spring 就不得不为其提前创建代理对象，否则注入的就是一个原始对象，而不是代理对象</code></p>
<p><code>Spring 的做法就是在 ObjectFactory 中去提前创建代理对象。它会执行 getObject() 方法来获取到 Bean。</code></p>
<p>因为提前进行了代理，避免对后面重复创建代理对象，会在 earlyProxyReferences 中记录已被代理的对象。</p>
<p><strong>解决循环依赖必须要三级缓存吗</strong></p>
<p>如果没有 AOP 代理，二级缓存可以解决问题，但是有 AOP 代理的情况下，只用二级缓存就意味着所有 Bean 在实例化后就要完成 AOP 代理，这样违背了 Spring 设计的原则，Spring 在设计之初就是通过 AnnotationAwareAspectJAutoProxyCreator 这个后置处理器来在 Bean 生命周期的最后一步来完成 AOP 代理，而不是在实例化后就立马进行 AOP 代理。</p>
<h2 id="Spring-何时进行AOP"><a href="#Spring-何时进行AOP" class="headerlink" title="Spring 何时进行AOP"></a><strong>Spring 何时进行AOP</strong></h2><p>通过上面的内容我们已经解决了循环依赖的问题，在循环依赖中，我们提前进行了Bean的AOP代理工作，但是在正常情况下，Bean的AOP又是在什么时候进行的呢？</p>
<p>Spring AOP代理对象生成时机分为两类：</p>
<p>提前和非提前生成代理对象</p>
<p>提前生成代理对象就是发生了循环依赖时，利用三级缓存，生成代理对象，将代理对象注入实例化对象中。</p>
<p>非提前生成代理对象，是在bean初始化后，调用BeanPostProcessor去完成7个BeanPostProcessor子类(其中有一个BeanPostProcessor专门用来做AOP工作)的调用，来生成AOP代理对象。</p>
<img src="/wang-cheng/2022/03/20/%E9%9D%A2%E8%AF%95%E9%A2%98-%E5%9B%9B/Bean%E7%9A%84AOP%E6%B5%81%E7%A8%8B.png" class title="Bean的AOP流程">

    </div>

    
    
    

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/wang-cheng/tags/%E9%9D%A2%E8%AF%95%E9%A2%98/" rel="tag"># 面试题</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/wang-cheng/2022/03/19/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%B8%89/" rel="prev" title="面试题(三)">
      <i class="fa fa-chevron-left"></i> 面试题(三)
    </a></div>
      <div class="post-nav-item">
    <a href="/wang-cheng/2022/03/22/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%BA%94/" rel="next" title="面试题(五)">
      面试题(五) <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B9%B6%E5%8F%91%E3%80%81%E5%B9%B6%E8%A1%8C%E3%80%81%E4%B8%B2%E8%A1%8C%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">1.</span> <span class="nav-text">并发、并行、串行的区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B9%B6%E5%8F%91%E7%9A%84%E4%B8%89%E5%A4%A7%E7%89%B9%E6%80%A7"><span class="nav-number">2.</span> <span class="nav-text">并发的三大特性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8%E7%BA%BF%E7%A8%8B%E6%B1%A0%EF%BC%9F%E8%A7%A3%E9%87%8A%E4%B8%8B%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%8F%82%E6%95%B0%EF%BC%9F"><span class="nav-number">3.</span> <span class="nav-text">为什么要用线程池？解释下线程池参数？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AE%80%E8%BF%B0%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B"><span class="nav-number">4.</span> <span class="nav-text">简述线程池处理流程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E7%9A%84%E4%BD%9C%E7%94%A8%EF%BC%9F%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF%E5%85%88%E6%B7%BB%E5%8A%A0%E9%98%9F%E5%88%97%E8%80%8C%E4%B8%8D%E6%98%AF%E5%85%88%E5%88%9B%E5%BB%BA%E6%9C%80%E5%A4%A7%E7%BA%BF%E7%A8%8B"><span class="nav-number">5.</span> <span class="nav-text">线程池中阻塞队列的作用？为什么是先添加队列而不是先创建最大线程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E7%BA%BF%E7%A8%8B%E5%A4%8D%E7%94%A8%E5%8E%9F%E7%90%86"><span class="nav-number">6.</span> <span class="nav-text">线程池中线程复用原理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Spring%E6%98%AF%E4%BB%80%E4%B9%88"><span class="nav-number">7.</span> <span class="nav-text">Spring是什么</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AF%B9AOP%E7%9A%84%E7%90%86%E8%A7%A3"><span class="nav-number">8.</span> <span class="nav-text">对AOP的理解</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AF%B9IOC%E7%9A%84%E7%90%86%E8%A7%A3"><span class="nav-number">9.</span> <span class="nav-text">对IOC的理解</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#BeanFactory%E5%92%8CApplicationContext%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB"><span class="nav-number">10.</span> <span class="nav-text">BeanFactory和ApplicationContext有什么区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8F%8F%E8%BF%B0%E4%B8%80%E4%B8%8BSpring-Bean%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="nav-number">11.</span> <span class="nav-text">描述一下Spring Bean的生命周期</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%A7%A3%E9%87%8A%E4%B8%8BSpring%E6%94%AF%E6%8C%81%E7%9A%84%E5%87%A0%E7%A7%8Dbean%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F"><span class="nav-number">12.</span> <span class="nav-text">解释下Spring支持的几种bean的作用域</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Spring%E6%A1%86%E6%9E%B6%E4%B8%AD%E7%9A%84%E5%8D%95%E4%BE%8BBean%E6%98%AF%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E7%9A%84%E5%90%97"><span class="nav-number">13.</span> <span class="nav-text">Spring框架中的单例Bean是线程安全的吗</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Spring%E6%A1%86%E6%9E%B6%E4%B8%AD%E9%83%BD%E7%94%A8%E4%BA%86%E5%93%AA%E4%BA%9B%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F"><span class="nav-number">14.</span> <span class="nav-text">Spring框架中都用了哪些设计模式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Spring-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%E4%B8%AD%E7%9A%84%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96%E9%97%AE%E9%A2%98"><span class="nav-number">15.</span> <span class="nav-text">Spring 依赖注入中的循环依赖问题</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%89%E7%A7%8D%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96%E7%9A%84%E6%83%85%E5%86%B5"><span class="nav-number">15.1.</span> <span class="nav-text">三种循环依赖的情况</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95"><span class="nav-number">15.2.</span> <span class="nav-text">解决方法</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Spring-%E4%BD%95%E6%97%B6%E8%BF%9B%E8%A1%8CAOP"><span class="nav-number">16.</span> <span class="nav-text">Spring 何时进行AOP</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">王诚</p>
  <div class="site-description" itemprop="description">命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/wang-cheng/archives/">
        
          <span class="site-state-item-count">32</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/wang-cheng/tags/">
          
        <span class="site-state-item-count">12</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">王诚</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/wang-cheng/lib/anime.min.js"></script>
  <script src="/wang-cheng/lib/velocity/velocity.min.js"></script>
  <script src="/wang-cheng/lib/velocity/velocity.ui.min.js"></script>

<script src="/wang-cheng/js/utils.js"></script>

<script src="/wang-cheng/js/motion.js"></script>


<script src="/wang-cheng/js/schemes/pisces.js"></script>


<script src="/wang-cheng/js/next-boot.js"></script>




  















  

  

  

</body>
</html>
